library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity icache_ctrl is port(
  clk, nrst         : in  std_logic;
  hit               : in  std_logic;
  icache_ren        : in  std_logic;
  addr              : in  std_logic_vector(31 downto 0);
  data_in           : in  std_logic_vector(31 downto 0);
  icacheWait        : in  std_logic;
  tag               : out std_logic_vector(25 downto 0);
  index             : out std_logic_vector(3 downto 0);
  data_out          : out std_logic_vector(31 downto 0);
  addr_out          : out std_logic_vector(31 downto 0);
  cpuWait           : out std_logic;
  icache_memRequest : out std_logic;
  icache_wen        : out std_logic);
end icache_ctrl;

architecture instr_cache_ctrl of icache_ctrl is
  type   state_type is(idle, miss);
  signal currState, nextState : state_type;
  signal t_tag                : std_logic_vector(25 downto 0);
  signal t_index              : std_logic_vector(3 downto 0);
begin

  tag   <= t_tag;
  index <= t_index;

  t_tag   <= addr(31 downto 6);
  t_index <= addr(5 downto 2);



  icache_state : process(clk, nrst)
  begin
    if nrst = '0' then
      currState <= idle;
    elsif rising_edge(clk) then
      currState <= nextState;
    end if;
  end process icache_state;

  nexttstate : process(hit, currState, icache_ren, icacheWait)
  begin
    
    nextState <= currState;
    case currState is
      when idle =>
        if hit = '0' and icache_ren = '1' then
          nextState <= miss;
        end if;
      when miss =>
        if(icacheWait = '0') then
          nextState <= idle;
        end if;
    end case;
  end process nexttstate;

  outp : process (currState, hit, icache_ren, icacheWait, addr, data_in)
  begin  -- process
    cpuWait           <= '1';
    icache_memRequest <= '0';
    icache_wen        <= '0';
    addr_out <= (others => '0');
    data_out <= (others => '0');
    case currState is
      when idle =>
        cpuWait <= ( not hit and icache_ren ) or icacheWait;
        if(hit = '1') then
          data_out <= data_in;
        else
          data_out <= (others => '0');
        end if;
      when miss =>
        icache_wen        <= not icacheWait;
        icache_memRequest <= '1';
        addr_out <= addr;
    end case;
  end process;
  
end;
